class Row:
  id = 0
  dists = {}
  def __init__(o,t,data):
    Row.id += 1
    o.id = Row.id
    o.table = t
    o.data = data
  def klassi(o) : return [len(o.data) - 1]
  def discretize(o,breaks) :
    for col in o.table.nums:
      o.data[col] = bin(o.data[col],breaks[col]) 
  def __sub__(o1,o2):
    if o1.id > o2.id: 
     o1,o2 = o2,o1
    key = (o1.id,o2.id)
    if key in Row.dists : 
      return Row.dists[key]
    else:
      out = Row.dists[key] = distance(o1,o2,o1.table.header)
      return out
  def __repr__(o) : return str({ o.id : o.data })
  
def distance(o1,o2,things):
  n=total=0
  for col,thing in enumerate(things):
    if thing.isKlass : continue
    n  += 1
    a   = o1.data[col]
    b   = o2.data[col]
    tmp = 1
    if a == b:
      if a != '?' : tmp=0
    else:
      if thing.isNumeric():
        lo = thing.min
        hi = thing.max
        if lo == hi: tmp = 0
        else:
          half = (hi - lo)/2.0 
          if a == '?' : a = (lo if b > half else hi)
          if b == '?' : b = (lo if a > half else hi)
          a   = (a - lo) / (hi - lo)
          b   = (b - lo) / (hi - lo)
          tmp = a - b
    total += thing.weight*(tmp**2)
  return total**0.5/n**0.5  

